//
//  MPSNetWorkOperationManager.m
//  MiaoPai
//
//  Created by jiaxuzhou on 2017/5/24.
//  Copyright © 2017年 jiaxuzhou. All rights reserved.
//

#import "MPSNetWorkOperationManager.h"
#import "MPCNetWorkOperation.h"
#import <CommonCrypto/CommonDigest.h>


@interface MPSNetWorkOperationManager ()


@property (nonatomic, strong) NSMutableDictionary *dictOpKeyCache;

/// 缓存操作
@property (nonatomic, strong) NSMutableDictionary *dictOpCache;

/// GCD
@property (nonatomic, strong) dispatch_semaphore_t gcdSemaphore;

@property (nonatomic, strong) NSOperationQueue *queue;


@end


@implementation MPSNetWorkOperationManager

+ (instancetype)shareOperationManager
{
    static MPSNetWorkOperationManager *sharedInstance;
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^
    {
        sharedInstance = [[MPSNetWorkOperationManager alloc] init];
    });
    
    return sharedInstance;
}

- (dispatch_queue_t)gcdQueue
{
    if (_gcdQueue == nil)
    {
        _gcdQueue = dispatch_queue_create("Customer_MP_GCD_Queue", DISPATCH_QUEUE_SERIAL);
    }
    
    return _gcdQueue;
}

- (dispatch_queue_t)gcdAsynQueue
{
    if (_gcdAsynQueue == nil)
    {
        _gcdAsynQueue = dispatch_queue_create("Customer_MP_GCD_ASYN_Queue", DISPATCH_QUEUE_CONCURRENT);
    }
    
    return _gcdAsynQueue;
}


- (dispatch_semaphore_t)gcdSemaphore
{
    if (_gcdSemaphore == nil)
    {
        /// 同时只允许一个任务执行
        _gcdSemaphore = dispatch_semaphore_create(1);
    }
    
    return _gcdSemaphore;
}

- (NSOperationQueue *)queue
{
    if (_queue == nil)
    {
        _queue = [[NSOperationQueue alloc] init];
    }
    
    return _queue;
}

- (NSMutableDictionary *)dictOpKeyCache
{
    if (_dictOpKeyCache == nil)
    {
        _dictOpKeyCache = [NSMutableDictionary dictionary];
    }
    
    return _dictOpKeyCache;
}

- (NSMutableDictionary *)dictOpCache
{
    if (_dictOpCache == nil)
    {
        _dictOpCache = [NSMutableDictionary dictionary];
    }
    
    return _dictOpCache;
}

/// 忽略多余的请求
- (void)addOperationIgnoreMoreWithView:(UIView *)viewIndiView
                                params:(NSDictionary *)dicParams
                                   url:(NSString *)strUrl
                              uniqueId:(id)unique
                               success:(void (^)(MPBNetWorking *req,MPURLSessionTask *task,id unique))reqFinishedBlock
                                failed:(void (^)(MPBNetWorking *req,MPURLSessionTask *task,id unique))reqFailedBlock
{
    if (dicParams == nil)
    {
        dicParams = @{};
    }
    
    
    /// 经过 MD5 加密的 key
    NSString *str2MD5 = [NSString stringWithFormat:@"%@&%@", [self convertToJsonData:dicParams], strUrl];
    NSString *strMd5Key = [self MD5String:str2MD5];
    
    /// 判断是否存在于缓存
    if ([self.dictOpKeyCache objectForKey:strMd5Key])
    {
        return;
    }
    
    __weak typeof(self) weadS = self;
    
    /// 最多同时执行N个请求 其他的不处理，（可能会造成前段UI与接口数据不匹配，不建议）
     long semT = dispatch_semaphore_wait(self.gcdSemaphore, DISPATCH_TIME_NOW);
     
     if (semT != 0) return;
    
    [self.dictOpKeyCache setObject:strMd5Key forKey:strMd5Key];
    dispatch_async(self.gcdQueue, ^
                   {
                       
                       MPCNetWorkOperation *operation = [MPCNetWorkOperation operationWithparams:dicParams
                                                                                           url:strUrl
                                                                                      uniqueId:unique
                                                                                       success:^(MPBNetWorking *req, MPURLSessionTask *task,id unique)
                       {
                           reqFinishedBlock(req,task,unique);
                           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), weadS.gcdQueue, ^
                                          {
                                              [weadS.dictOpCache removeObjectForKey:strMd5Key];
                                              [weadS.dictOpKeyCache removeObjectForKey:strMd5Key];
                                          });

                       } failed:^(MPBNetWorking *req, MPURLSessionTask *task,id unique)
                       {
                           reqFailedBlock(req,task,unique);
                           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), weadS.gcdQueue, ^
                                          {
                                              [weadS.dictOpCache removeObjectForKey:strMd5Key];
                                              [weadS.dictOpKeyCache removeObjectForKey:strMd5Key];
                                          });

                       }];
                       
                       [weadS.dictOpCache setObject:operation forKey:strMd5Key];
                       
                       [operation start];

                       dispatch_semaphore_signal(weadS.gcdSemaphore);
                       
                   });
}

/// 延迟多余的请求
- (void)addOperationDelayMoreWithView:(UIView *)viewIndiView
                               params:(NSDictionary *)dicParams
                                  url:(NSString *)strUrl
                             uniqueId:(id)unique
                              success:(void (^)(MPBNetWorking *req,MPURLSessionTask *task,id unique))reqFinishedBlock
                               failed:(void (^)(MPBNetWorking *req,MPURLSessionTask *task,id unique))reqFailedBlock
{
    if (dicParams == nil)
    {
        dicParams = @{};
    }
    
    /// 经过 MD5 加密的 key
    NSString *str2MD5 = [NSString stringWithFormat:@"%@&%@", [self convertToJsonData:dicParams], strUrl];
    NSString *strMd5Key = [self MD5String:str2MD5];
    
    __weak typeof(self) weadS = self;
    

    /// 多余的请求等待
    
    dispatch_async(self.gcdAsynQueue, ^
                   {
                       
                       dispatch_semaphore_wait(self.gcdSemaphore, DISPATCH_TIME_FOREVER);

                       MPCNetWorkOperation *operation = [MPCNetWorkOperation operationWithparams:dicParams
                                                                                           url:strUrl
                                                                                      uniqueId:unique
                                                                                       success:^(MPBNetWorking *req, MPURLSessionTask *task,id unique)
                       {
                           reqFinishedBlock(req,task,unique);
                           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), weadS.gcdQueue, ^
                                          {
                                              [weadS.dictOpCache removeObjectForKey:strMd5Key];
                                          });
                       }
                                                                                          failed:^(MPBNetWorking *req, MPURLSessionTask *task,id unique)
                       {
                           reqFailedBlock(req,task,unique);
                           dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.1 * NSEC_PER_SEC)), weadS.gcdQueue, ^
                                          {
                                              [weadS.dictOpCache removeObjectForKey:strMd5Key];
                                          });

                       }];
                       
                       [weadS.dictOpCache setObject:operation forKey:strMd5Key];
                       [operation start];
                       
                       dispatch_semaphore_signal(weadS.gcdSemaphore);

                   });
}

- (void)sendRequestWithParam:(NSDictionary *)dicParam url:(NSString *)strUrl
{
    MPCNetWorkOperation *operation = [MPCNetWorkOperation operationWithparams:dicParam
                                                                          url:strUrl
                                                                     uniqueId:nil
                                                                      success:nil
                                                                       failed:nil];
    
    [self.queue addOperation:operation];
}

// 字典转json字符串方法

-(NSString *)convertToJsonData:(NSDictionary *)dict

{
    NSError *error;
    
    NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:&error];
    
    NSString *jsonString = @"";
    
    if (jsonData)
    {
        jsonString = [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding];
    }
    
    NSMutableString *mutStr = [NSMutableString stringWithString:jsonString];
    
    return mutStr;
}

- (NSString *)MD5String:(NSString *)str
{
    const char *src = [str UTF8String];
    unsigned char result[CC_MD5_DIGEST_LENGTH];
    CC_MD5(src, (CC_LONG)strlen(src), result);
    
    NSString *ret = [[NSString alloc] initWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",
                     result[0], result[1], result[2], result[3],
                     result[4], result[5], result[6], result[7],
                     result[8], result[9], result[10], result[11],
                     result[12], result[13], result[14], result[15]
                     ];
    
    return [ret lowercaseString];
}


@end
